/*     */ package com.zimbra.cs.store;
/*     */ 
/*     */ import com.zimbra.common.localconfig.DebugConfig;
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.ByteUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import java.io.File;
/*     */ import java.io.FileNotFoundException;
/*     */ import java.io.FileOutputStream;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.io.OutputStream;
/*     */ import java.nio.ByteBuffer;
/*     */ import java.nio.channels.FileChannel;
/*     */ import java.security.MessageDigest;
/*     */ import java.security.NoSuchAlgorithmException;
/*     */ import java.util.zip.GZIPOutputStream;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class BlobBuilder
/*     */ {
/*     */   protected Blob blob;
/*     */   private long sizeHint;
/*     */   protected boolean disableCompression;
/*     */   private boolean disableDigest;
/*     */   private MessageDigest digest;
/*     */   private OutputStream out;
/*     */   private FileChannel fc;
/*     */   private long totalBytes;
/*     */   private boolean finished;
/*     */   private byte[] buf;
/*  48 */   private int bufLen = 0;
/*  49 */   private boolean compressionThresholdExceeded = false;
/*     */   
/*     */   protected BlobBuilder(Blob targetBlob) {
/*  52 */     this.blob = targetBlob;
/*     */   }
/*     */   
/*     */   public BlobBuilder setSizeHint(long size) {
/*  56 */     this.sizeHint = size;
/*  57 */     return this;
/*     */   }
/*     */   
/*     */   public long getSizeHint() {
/*  61 */     return this.sizeHint;
/*     */   }
/*     */   
/*     */   public long getTotalBytes() {
/*  65 */     return this.totalBytes;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public BlobBuilder disableCompression(boolean disable)
/*     */   {
/*  74 */     this.disableCompression = disable;
/*  75 */     return this;
/*     */   }
/*     */   
/*     */   protected int getCompressionThreshold() {
/*  79 */     return 0;
/*     */   }
/*     */   
/*     */   public BlobBuilder disableDigest(boolean disable) {
/*  83 */     this.disableDigest = disable;
/*  84 */     return this;
/*     */   }
/*     */   
/*     */   public BlobBuilder init() throws IOException, ServiceException {
/*  88 */     if (!this.disableDigest) {
/*     */       try {
/*  90 */         this.digest = MessageDigest.getInstance("SHA-256");
/*     */       } catch (NoSuchAlgorithmException e) {
/*  92 */         throw ServiceException.FAILURE("SHA-256 digest not found", e);
/*     */       }
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*  99 */     this.out = createOutputStream(this.blob.getFile());
/* 100 */     this.fc = getFileChannel();
/*     */     
/* 102 */     if (useCompression()) {
/* 103 */       this.buf = new byte[getCompressionThreshold()];
/*     */ 
/*     */ 
/*     */     }
/* 107 */     else if (!this.disableCompression) {
/* 108 */       this.blob.setCompressed(false);
/*     */     }
/*     */     
/*     */ 
/* 112 */     return this;
/*     */   }
/*     */   
/*     */   protected OutputStream createOutputStream(File file) throws FileNotFoundException
/*     */   {
/* 117 */     return new FileOutputStream(file);
/*     */   }
/*     */   
/*     */   protected FileChannel getFileChannel()
/*     */   {
/* 122 */     return ((FileOutputStream)this.out).getChannel();
/*     */   }
/*     */   
/*     */   protected boolean useCompression() throws IOException
/*     */   {
/* 127 */     return false;
/*     */   }
/*     */   
/* 130 */   private static final int BUFLEN = Math.max(LC.zimbra_store_copy_buffer_size_kb.intValue(), 1) * 1024;
/*     */   
/*     */   public BlobBuilder append(InputStream in) throws IOException {
/* 133 */     byte[] buffer = new byte[BUFLEN];
/*     */     int numRead;
/* 135 */     while ((numRead = in.read(buffer)) >= 0) {
/* 136 */       append(buffer, 0, numRead);
/*     */     }
/* 138 */     return this;
/*     */   }
/*     */   
/*     */   public BlobBuilder append(byte[] b) throws IOException {
/* 142 */     return append(b, 0, b.length);
/*     */   }
/*     */   
/*     */   public BlobBuilder append(byte[] b, int off, int len) throws IOException {
/* 146 */     if (this.finished) {
/* 147 */       throw new IllegalStateException("BlobBuilder is finished");
/*     */     }
/* 149 */     checkInitialized();
/*     */     
/* 151 */     if ((!this.compressionThresholdExceeded) && (useCompression())) {
/* 152 */       if (this.bufLen + len <= getCompressionThreshold())
/*     */       {
/* 154 */         System.arraycopy(b, off, this.buf, this.bufLen, len);
/* 155 */         this.bufLen += len;
/* 156 */         this.totalBytes = this.bufLen;
/* 157 */         return this;
/*     */       }
/*     */       
/*     */ 
/*     */ 
/* 162 */       this.out = new GZIPOutputStream(this.out);
/* 163 */       writeToFile(this.buf, 0, this.bufLen);
/* 164 */       this.blob.setCompressed(true);
/* 165 */       this.compressionThresholdExceeded = true;
/*     */     }
/*     */     
/* 168 */     writeToFile(b, off, len);
/* 169 */     this.totalBytes += len;
/* 170 */     return this;
/*     */   }
/*     */   
/*     */   private void writeToFile(byte[] b, int off, int len) throws IOException {
/* 174 */     if (len > 0) {
/*     */       try {
/* 176 */         this.out.write(b, off, len);
/* 177 */         if (this.digest != null) {
/* 178 */           this.digest.update(b, off, len);
/*     */         }
/*     */       } catch (IOException e) {
/* 181 */         dispose();
/* 182 */         throw e;
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public BlobBuilder append(ByteBuffer bb) throws IOException {
/* 188 */     if (!bb.hasArray()) {
/* 189 */       throw new IllegalArgumentException("ByteBuffer must have backing array");
/*     */     }
/* 191 */     append(bb.array(), bb.arrayOffset() + bb.position(), bb.remaining());
/* 192 */     bb.position(bb.limit());
/* 193 */     return this;
/*     */   }
/*     */   
/*     */   private void checkInitialized() throws IOException {
/* 197 */     if (this.out == null) {
/*     */       try {
/* 199 */         init();
/*     */       } catch (Exception e) {
/* 201 */         throw ((IOException)new IOException("Unable to initialize BlobBuilder").initCause(e));
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   public Blob finish() throws IOException, ServiceException
/*     */   {
/* 208 */     if (this.finished) {
/* 209 */       return this.blob;
/*     */     }
/* 211 */     checkInitialized();
/*     */     
/* 213 */     if ((useCompression()) && (!this.compressionThresholdExceeded))
/*     */     {
/*     */ 
/* 216 */       writeToFile(this.buf, 0, this.bufLen);
/* 217 */       this.blob.setCompressed(false);
/*     */     }
/*     */     try
/*     */     {
/* 221 */       if (!DebugConfig.disableMessageStoreFsync) {
/* 222 */         this.out.flush();
/* 223 */         if (this.fc != null) {
/* 224 */           this.fc.force(true);
/*     */         }
/*     */       }
/*     */     } catch (IOException e) {
/* 228 */       dispose();
/* 229 */       throw e;
/*     */     } finally {
/* 231 */       ByteUtil.closeStream(this.out);
/*     */     }
/*     */     
/*     */ 
/* 235 */     if (this.digest != null) {
/* 236 */       this.blob.setDigest(ByteUtil.encodeFSSafeBase64(this.digest.digest()));
/* 237 */       this.blob.setRawSize(this.totalBytes);
/*     */     }
/* 239 */     if (ZimbraLog.store.isDebugEnabled()) {
/* 240 */       ZimbraLog.store.debug("stored " + this);
/*     */     }
/* 242 */     this.finished = true;
/* 243 */     return this.blob;
/*     */   }
/*     */   
/*     */   public String toString() {
/* 247 */     File file = this.blob.getFile();
/*     */     
/* 249 */     String compressed = "???";
/*     */     try {
/* 251 */       compressed = Boolean.toString(this.blob.isCompressed());
/*     */     } catch (IOException ioe) {}
/* 253 */     return file.getAbsolutePath() + ": data size=" + this.totalBytes + ", file size=" + file.length() + ", isCompressed=" + compressed;
/*     */   }
/*     */   
/*     */   public Blob getBlob() {
/* 257 */     if (!this.finished)
/* 258 */       throw new IllegalStateException("Blob builder not finished");
/* 259 */     return this.blob;
/*     */   }
/*     */   
/*     */   public boolean isFinished() {
/* 263 */     return this.finished;
/*     */   }
/*     */   
/*     */   public void dispose()
/*     */   {
/* 268 */     if (this.blob != null) {
/* 269 */       this.finished = true;
/* 270 */       ByteUtil.closeStream(this.out);
/* 271 */       StoreManager.getInstance().quietDelete(this.blob);
/* 272 */       this.blob = null;
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/store/BlobBuilder.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */